#region using
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using AwesomeTanks.Sources.Tools;
using AwesomeTanks.Sources.Particles;
using AwesomeTanks.Sources.Screens;
using AwesomeTanks.Sources.Media;
using AwesomeTanks.Sources.GameElements.ShootElements;
using AwesomeTanks.Sources.GameElements.ShootElements.Weapons;
using ShapeBlaster;
using AwesomeTanks.Sources.Shape;
#endregion

namespace AwesomeTanks.Sources.GameElements.TankElements
{
    /// <summary>
    /// The model of a Tank in AwesomeTanks
    /// </summary>
    public class Tank : MovableSprite
    {
        #region Fields
        public const float TANK_LAYER_DEPTH = 0.8f;

        public Turret Turret { get; set; }
        public Weapon Weapon { get; set; }
        public Weapon SecondaryWeapon { get; set; }
        public bool ExhaustFire { get; set; }
        public int CurrentLife { get; set; }
        public int MaxLife { get; set; }
        public List<Circle> HitboxList { get; set; }

        public static Random rand = new Random();
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="Tank"/> class.
        /// <param name="position">The position.</param>
        /// <param name="speed">The speed.</param>
        /// <param name="life">The life.</param>
        /// </summary>
        public Tank()
            : this(1)
        {
        }

        public Tank(int life)
            : this(Vector2.Zero, Vector2.Zero, life)
        {
        }

        public Tank(Vector2 position, Vector2 speed, int life)
            : base(Art.SpriteSheet, Art.BaseTankSourceRectangle, position, speed)
        {
            this.LayerDepth = TANK_LAYER_DEPTH;
            this.MaxLife = life;
            this.CurrentLife = life;
            this.Origin = Art.BaseTankOrigin;
            this.Turret = new Turret(this.Position);
            this.Weapon = new Gatling();
            this.SecondaryWeapon = new Rocket();

            this.HitboxList = new List<Circle>();
            this.HitboxList.Add(new Circle(Vector2.Zero, this.SourceRectangle.Value.Width / 2));
            this.HitboxList.Add(new Circle(Vector2.Zero, this.SourceRectangle.Value.Width / 2));
        }
        #endregion

        #region Update and Draw
        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            this.UpdateHitboxes();

            if (Speed.LengthSquared() > 0)
            {
                Vector2 reversedSpeed = new Vector2(-Speed.Y, Speed.X);
                this.Rotation = reversedSpeed.ToAngle();

                if (ExhaustFire)
                {
                    this.MakeExhaustFire();
                }
                else
                {
                    ExhaustFire = true;
                }
            }

            //Update the Tank Turret
            this.Turret.Update(this.Position);
        }

        /// <summary>
        /// Draw this Tank in the specified sprite batch.
        /// </summary>
        /// <param name="spriteBatch">The sprite batch.</param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            if (this != null)
            {
                base.Draw(spriteBatch);
                //Call The Turret's Draw function
                this.Turret.Draw(spriteBatch);
            }
        }

        public void UpdateHitboxes() {

            Vector2 centerCircle1 = new Vector2(this.Position.X,
            this.Position.Y + this.SourceRectangle.Value.Height / 2 - this.SourceRectangle.Value.Width / 2);
            Vector2 centerCircle2 = new Vector2(this.Position.X,
            this.Position.Y - this.SourceRectangle.Value.Height / 2 + this.SourceRectangle.Value.Width / 2);

            centerCircle1 = Circle.RotateVector2(centerCircle1, this.Rotation, this.Position);
            centerCircle2 = Circle.RotateVector2(centerCircle2, this.Rotation, this.Position);

            this.HitboxList.ElementAt(0).Center = centerCircle1;
            this.HitboxList.ElementAt(1).Center = centerCircle2;

        }
        #endregion

        #region Methods

        /// <summary>
        /// Makes the exhaust fire with Particles for the Tank when he moves.
        /// </summary>
        private void MakeExhaustFire()
        {
            if (Speed.LengthSquared() > 0.1f)
            {

                Quaternion rot = Quaternion.CreateFromYawPitchRoll(0f, 0f, Rotation);
                double t = GameplayScreen.GameTime.TotalGameTime.TotalSeconds;

                // The primary velocity of the particles is 3 pixels/frame in the direction opposite to which the ship is travelling.
                Vector2 baseVel = Speed.ScaleTo(6);

                // Calculate the sideways velocity for the two side streams. The direction is perpendicular to the ship's velocity and the
                // magnitude varies sinusoidally.

                Vector2 perpVel = new Vector2(baseVel.Y, -baseVel.X) * (0.6f * (float)Math.Sin(t * 10));
                Vector2 vel1 = baseVel + perpVel + rand.NextVector2(0, 0.3f);
                Vector2 vel2 = baseVel - perpVel + rand.NextVector2(0, 0.3f);
                Color sideColor = new Color(200, 38, 9);	// deep red
                Color midColor = new Color(255, 187, 30);	// orange-yellow
                Vector2 pos = this.Position + Vector2.Transform(new Vector2(-17, 65), rot);	// position of the ship's exhaust pipe.
                const float alpha = 0.7f;

                // left particle stream
                Vector2 velMid = baseVel + rand.NextVector2(0, 1);
                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.ParticlePosition.X, Art.ParticlePosition.Y, Art.ParticleDimension.X, Art.ParticleDimension.Y), Color.White * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(velMid, ParticleType.Enemy));
                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.GlowPosition.X, Art.GlowPosition.Y, Art.GlowDimension.X, Art.GlowDimension.Y), midColor * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(velMid, ParticleType.Enemy));


                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.ParticlePosition.X, Art.ParticlePosition.Y, Art.ParticleDimension.X, Art.ParticleDimension.Y), Color.White * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(vel1, ParticleType.Enemy));
                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.ParticlePosition.X, Art.ParticlePosition.Y, Art.ParticleDimension.X, Art.ParticleDimension.Y), Color.White * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(vel2, ParticleType.Enemy));

                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.GlowPosition.X, Art.GlowPosition.Y, Art.GlowDimension.X, Art.GlowDimension.Y), sideColor * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(vel1, ParticleType.Enemy));
                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.GlowPosition.X, Art.GlowPosition.Y, Art.GlowDimension.X, Art.GlowDimension.Y), sideColor * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(vel2, ParticleType.Enemy));


                pos = this.Position + Vector2.Transform(new Vector2(17, 65), rot);

                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.ParticlePosition.X, Art.ParticlePosition.Y, Art.ParticleDimension.X, Art.ParticleDimension.Y), Color.White * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(velMid, ParticleType.Enemy));
                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.GlowPosition.X, Art.GlowPosition.Y, Art.GlowDimension.X, Art.GlowDimension.Y), midColor * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(velMid, ParticleType.Enemy));


                // side particle streams

                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.ParticlePosition.X, Art.ParticlePosition.Y, Art.ParticleDimension.X, Art.ParticleDimension.Y), Color.White * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(vel1, ParticleType.Enemy));
                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.ParticlePosition.X, Art.ParticlePosition.Y, Art.ParticleDimension.X, Art.ParticleDimension.Y), Color.White * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(vel2, ParticleType.Enemy));

                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.GlowPosition.X, Art.GlowPosition.Y, Art.GlowDimension.X, Art.GlowDimension.Y), sideColor * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(vel1, ParticleType.Enemy));
                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, pos, new Rectangle(Art.GlowPosition.X, Art.GlowPosition.Y, Art.GlowDimension.X, Art.GlowDimension.Y), sideColor * alpha, 60f, new Vector2(0.5f, 1),
                    new ParticleState(vel2, ParticleType.Enemy));

            }
        }

        /// <summary>
        /// Create the Explosion with Particles when the Tank is destroyed
        /// </summary>
        public void Explode()
        {
            float hue1 = rand.NextFloat(0, 6);
            float hue2 = (hue1 + rand.NextFloat(0, 2)) % 6f;
            Color color1 = ColorUtil.HSVToColor(hue1, 0.5f, 1);
            Color color2 = ColorUtil.HSVToColor(hue2, 0.5f, 1);

            for (int i = 0; i < 1000; i++)
            {
                float speed = 18f * (1f - 1 / rand.NextFloat(1, 10));
                var state = new ParticleState()
                {
                    Velocity = rand.NextVector2(speed, speed),
                    Type = ParticleType.Enemy,
                    LengthMultiplier = 1
                };

                Color color = Color.Lerp(color1, color2, rand.NextFloat(0, 1));
                GameplayScreen.ParticleManager.CreateParticle(Art.SpriteSheet, Position, new Rectangle(Art.ParticlePosition.X, Art.ParticlePosition.Y, Art.ParticleDimension.X, Art.ParticleDimension.Y), color, 190, 1.5f, state);
            }

            if (!OptionsMenuScreen.MuteEffect)
            {
                Sound.TankExplosion.Play(Sound.SOUNDEFFECT_VOLUME, 0f, 0f);
            }
        }


        /// <summary>
        /// Gets the percentage life remaining.
        /// </summary>
        /// <returns></returns>
        public int GetPercentageLifeRemaining()
        {
            return (this.CurrentLife * 100 / this.MaxLife);
        }
        #endregion
    }

}
